package com.example.testmarkwon

import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.text.TextPaint
import android.text.style.MetricAffectingSpan
import com.example.testmarkwon.BuiltInVisitors.parentIsListItem
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.BlockHandlerDef
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.MarkwonSpansFactory
import io.noties.markwon.MarkwonVisitor
import io.noties.markwon.RenderProps
import io.noties.markwon.SpanFactory
import io.noties.markwon.core.CoreProps
import io.noties.markwon.core.CoreProps.HEADING_LEVEL
import io.noties.markwon.core.MarkwonTheme
import io.noties.markwon.core.spans.LastLineSpacingSpan
import org.commonmark.node.Heading
import org.commonmark.node.ListBlock
import org.commonmark.node.ListItem
import org.commonmark.node.Node
import org.commonmark.node.Paragraph

class MarkdownPlugin : AbstractMarkwonPlugin() {

    override fun configureVisitor(builder: MarkwonVisitor.Builder) {
        super.configureVisitor(builder)
        // 设置块处理器
        builder.blockHandler(NoDoubleEnterHandler())

        // 设置段落处理器
        BuiltInVisitors.paragraph(builder)
    }

    override fun configureTheme(builder: MarkwonTheme.Builder) {
        super.configureTheme(builder)
        // 隐藏标题下面的横线
        builder.headingBreakHeight(0)
        // 设置引用和列表的x轴偏移
        builder.blockMargin(14.dpInt)
        // 无序列表小图标的尺寸
        builder.bulletWidth(6.dpInt)
        // 设置分割线
        builder.thematicBreakHeight(1.dpInt)
        builder.thematicBreakColor(Color.parseColor("#E7E7E7"))
    }

    override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
        val commonMargin = 12.dpInt
        val listMargin = 8.dpInt
        builder.appendFactory(Heading::class.java, CustomHeadingSpanFactory())
        builder.appendFactory(Heading::class.java) { _, _ ->
            LastLineSpacingSpan.create(commonMargin)
        }
        builder.appendFactory(Paragraph::class.java) { _, _ ->
            // 如果在列表中，设置段落边距为8dp，否则为12dp
            val margin = if (parentIsListItem) listMargin else commonMargin
            LastLineSpacingSpan.create(margin)
        }
    }
}

private class NoDoubleEnterHandler : BlockHandlerDef() {
    override fun blockStart(visitor: MarkwonVisitor, node: Node) {
        visitor.ensureNewLine()
    }

    override fun blockEnd(visitor: MarkwonVisitor, node: Node) {
        // 不再自动添加双回车产生间距
    }
}

private class CustomHeadingSpan(
    private val level: Int,
    private val textSize: Float,
) : MetricAffectingSpan() {

    override fun updateDrawState(ds: TextPaint) {
        applySettings(ds)
    }

    override fun updateMeasureState(paint: TextPaint) {
        applySettings(paint)
    }

    private fun applySettings(paint: Paint) {
        paint.textSize = textSize
        paint.isFakeBoldText = false // 关闭伪粗体

        paint.typeface = when {
            level in 1..3 -> Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
            else -> Typeface.DEFAULT
        }
    }
}

private class CustomHeadingSpanFactory : SpanFactory {
    override fun getSpans(
        configuration: MarkwonConfiguration,
        props: RenderProps
    ): Any {
        val level = props.get(HEADING_LEVEL) ?: throw RuntimeException()
        val textSize = when (level) {
            1 -> 20.dp
            2 -> 18.dp
            3 -> 16.dp
            else -> 16.dp
        }
        return CustomHeadingSpan(level, textSize)
    }
}

/**
 * 这个类是从CorePlugin抄的
 */
private object BuiltInVisitors {

    var parentIsListItem: Boolean = false

    fun paragraph(builder: MarkwonVisitor.Builder) {
        builder.on(Paragraph::class.java) { visitor, paragraph ->
            val inTightList = isInTightList(paragraph)
            if (!inTightList) {
                visitor.blockStart(paragraph)
            }

            val length = visitor.length()
            visitor.visitChildren(paragraph)

            CoreProps.PARAGRAPH_IS_IN_TIGHT_LIST[visitor.renderProps()] = inTightList

            /**
             * 这个需求针对有序/无序列表：有序无序列表的ListItem之间的间距是8dp
             * 观察AST（抽象语法树）发现，不能简单地给ListItem增加段落边距
             * 因为ListItem可能嵌套，导致段落边距不正确
             *
             * 最终逻辑：
             * 如果paragraph的父节点是ListItem，则允许使用外部设置的段落边距
             * 外部设置的段落边距给paragraph：
             * builder.appendFactory(Paragraph::class.java) { _, _ ->
             *     LastLineSpacingSpan.create(30.dpInt)
             * }
             */
            parentIsListItem = paragraph.parent is ListItem

            // @since 1.1.1 apply paragraph span
            visitor.setSpansForNodeOptional(paragraph, length)

            if (!inTightList) {
                visitor.blockEnd(paragraph)
            }
        }
    }

    private fun isInTightList(paragraph: Paragraph): Boolean {
        val parent: Node? = paragraph.parent
        if (parent != null) {
            val gramps = parent.parent
            if (gramps is ListBlock) {
                return gramps.isTight
            }
        }
        return false
    }
}
